/*
 * Copyright (c) 2000, 2003, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */

package com.sun.corba.se.impl.interceptors;

import com.sun.corba.se.spi.orb.ORB;
import org.omg.PortableInterceptor.Current;
import org.omg.PortableInterceptor.InvalidSlot;
import org.omg.CORBA.Any;
import org.omg.CORBA.BAD_INV_ORDER;
import org.omg.CORBA.CompletionStatus;

import com.sun.corba.se.spi.logging.CORBALogDomains;
import com.sun.corba.se.impl.logging.OMGSystemException;

/**
 * PICurrent is the implementation of Current as specified in the Portable
 * Interceptors Spec orbos/99-12-02.
 * IMPORTANT: PICurrent is implemented with the assumption that get_slot()
 * or set_slot() will not be called in ORBInitializer.pre_init() and
 * post_init().
 */
public class PICurrent extends org.omg.CORBA.LocalObject implements Current {
    // slotCounter is used to keep track of ORBInitInfo.allocate_slot_id()
    private int slotCounter;

    // The ORB associated with this PICurrent object.
    private ORB myORB;

    private OMGSystemException wrapper;

    // True if the orb is still initialzing and get_slot and set_slot are not
    // to be called.
    private boolean orbInitializing;

    // ThreadLocal contains a stack of SlotTable which are used
    // for resolve_initial_references( "PICurrent" );
    private ThreadLocal threadLocalSlotTable = new ThreadLocal() {
        protected Object initialValue() {
            SlotTable table = new SlotTable(myORB, slotCounter);
            return new SlotTableStack(myORB, table);
        }
    };

    /**
     * PICurrent constructor which will be called for every ORB
     * initialization.
     */
    PICurrent(ORB myORB) {
        this.myORB = myORB;
        wrapper = OMGSystemException.get(myORB, CORBALogDomains.RPC_PROTOCOL);
        this.orbInitializing = true;
        slotCounter = 0;
    }

    /**
     * This method will be called from ORBInitInfo.allocate_slot_id( ).
     * simply returns a slot id by incrementing slotCounter.
     */
    int allocateSlotId() {
        int slotId = slotCounter;
        slotCounter = slotCounter + 1;
        return slotId;
    }

    /**
     * This method gets the SlotTable which is on the top of the
     * ThreadLocalStack.
     */
    SlotTable getSlotTable() {
        SlotTable table = (SlotTable) ((SlotTableStack) threadLocalSlotTable.get()).peekSlotTable();
        return table;
    }

    /**
     * This method pushes a SlotTable on the SlotTableStack. When there is
     * a resolve_initial_references("PICurrent") after this call. The new
     * PICurrent will be returned.
     */
    void pushSlotTable() {
        SlotTableStack st = (SlotTableStack) threadLocalSlotTable.get();
        st.pushSlotTable();
    }

    /**
     * This method pops a SlotTable on the SlotTableStack.
     */
    void popSlotTable() {
        SlotTableStack st = (SlotTableStack) threadLocalSlotTable.get();
        st.popSlotTable();
    }

    /**
     * This method sets the slot data at the given slot id (index) in the
     * Slot Table which is on the top of the SlotTableStack.
     */
    public void set_slot(int id, Any data) throws InvalidSlot {
        if (orbInitializing) {
            // As per ptc/00-08-06 if the ORB is still initializing, disallow
            // calls to get_slot and set_slot.  If an attempt is made to call,
            // throw a BAD_INV_ORDER.
            throw wrapper.invalidPiCall3();
        }

        getSlotTable().set_slot(id, data);
    }

    /**
     * This method gets the slot data at the given slot id (index) from the
     * Slot Table which is on the top of the SlotTableStack.
     */
    public Any get_slot(int id) throws InvalidSlot {
        if (orbInitializing) {
            // As per ptc/00-08-06 if the ORB is still initializing, disallow
            // calls to get_slot and set_slot.  If an attempt is made to call,
            // throw a BAD_INV_ORDER.
            throw wrapper.invalidPiCall4();
        }

        return getSlotTable().get_slot(id);
    }

    /**
     * This method resets all the slot data to null in the
     * Slot Table which is on the top of SlotTableStack.
     */
    void resetSlotTable() {
        getSlotTable().resetSlots();
    }

    /**
     * Called from ORB when the ORBInitializers are about to start
     * initializing.
     */
    void setORBInitializing(boolean init) {
        this.orbInitializing = init;
    }
}
